package com.gw.sponge.util;

import java.util.HashMap;
import java.util.Map;

/**
 * Description: 线程上下文对象映射
 * com.gw.sponge.util->ObjectMapThreadLocal
 *
 * @author YanAn
 * @date 2023/1/14 12:24
 */
public class ObjectMapThreadLocal {

	/**
	 * 线程上下文
	 */
	private static final ThreadLocal<Map<Object, Object>> CONTEXT = new ThreadLocal<>();

	/**
	 * 初始化线程上下文
	 *
	 * @return Map<Object, Object>
	 */
	public static Map<Object, Object> init() {
		HashMap<Object, Object> data = new HashMap<>(16);
		CONTEXT.set(data);
		return data;
	}

	/**
	 * 拿到线程上下文
	 *
	 * @return Map<Object, Object>
	 */
	public static Map<Object, Object> getContext() {
		if (CONTEXT.get() == null) {
			init();
		}
		return CONTEXT.get();
	}

	/**
	 * 放入键值对
	 *
	 * @param key   键
	 * @param value 值
	 * @param <K>   Object的子类
	 * @param <V>   Object的子类
	 */
	public static <K extends Object, V extends Object> void put(K key, V value) {
		if (CONTEXT.get() == null) {
			init();
		}
		Map<Object, Object> contextMap = CONTEXT.get();
		contextMap.put(key, value);
	}

	/**
	 * 在上下文中获取指定键对应的值-指定返回对象类型
	 *
	 * @param key   键
	 * @param cType 返回对象类型
	 * @param <K>   Object的子类
	 * @param <C>   Object的子类
	 * @return 上下文中的指定键对应的值
	 */
	public static <K extends Object, C extends Object> C get(K key, Class<C> cType) {
		if (CONTEXT.get() == null) {
			init();
		}
		Map<Object, Object> contextMap = CONTEXT.get();
		C r = (C) contextMap.get(key);
		return r;
	}

	/**
	 * 在上下文中获取指定键对应的值
	 *
	 * @param key 键
	 * @param <K> Object的子类
	 * @return 上下文中指定键对应的值
	 */
	public static <K extends Object> Object get(K key) {
		if (CONTEXT.get() == null) {
			init();
		}
		Map<Object, Object> contextMap = CONTEXT.get();
		return contextMap.get(key);
	}

	/**
	 * 清除线程上下文，且清除LogKey
	 * 必须回收自定义的 ThreadLocal 变量，尤其在线程池场景下，线程经常会被复用，
	 * 如果不清理自定义的 ThreadLocal 变量，可能会影响后续业务逻辑和造成内存泄露等问题。
	 * 尽量在代理中使用 try-finally 块进行回收
	 */
	public static void clear() {
		if (CONTEXT != null) {
			CONTEXT.remove();
		}
	}

}
